package com.neusoft.neuiotms.dcam.workflow.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.persistence.EntityNotFoundException;
import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import com.neusoft.bizcore.activiti.dto.ProcessInstanceDTO;
import com.neusoft.bizcore.activiti.model.WorkOrder;
import com.neusoft.bizcore.activiti.repository.WorkOrderRepository;
import com.neusoft.bizcore.activiti.service.ProcessInstanceService;
import com.neusoft.bizcore.activiti.service.WorkOrderService;
import com.neusoft.bizcore.auth.common.bean.UserBean;
import com.neusoft.bizcore.web.constant.ExceptionConstants;
import com.neusoft.bizcore.web.dto.result.ResultListDTO;
import com.neusoft.bizcore.web.exception.UnitedException;
import com.neusoft.bizcore.web.support.Searchable;
import com.neusoft.neuiotms.common.constant.AHConstants;
import com.neusoft.neuiotms.dcam.constant.DCAMConsts;
import com.neusoft.neuiotms.dcam.fixed.converter.AssetConverter;
import com.neusoft.neuiotms.dcam.fixed.dto.AssetDTO;
import com.neusoft.neuiotms.dcam.fixed.dto.AssetLifeCycleDTO;
import com.neusoft.neuiotms.dcam.fixed.dto.WarehouseRecordDTO;
import com.neusoft.neuiotms.dcam.fixed.model.Asset;
import com.neusoft.neuiotms.dcam.fixed.repository.AssetRepository;
import com.neusoft.neuiotms.dcam.fixed.service.AssetLifeCycleService;
import com.neusoft.neuiotms.dcam.fixed.service.AssetService;
import com.neusoft.neuiotms.dcam.fixed.service.StorehouseService;
import com.neusoft.neuiotms.dcam.fixed.service.WarehouseRecordService;
import com.neusoft.neuiotms.dcam.workflow.converter.LingyongConfrimSLConverter;
import com.neusoft.neuiotms.dcam.workflow.converter.LingyongSLConverter;
import com.neusoft.neuiotms.dcam.workflow.dto.LingyongConfrimSLDTO;
import com.neusoft.neuiotms.dcam.workflow.dto.LingyongSLDTO;
import com.neusoft.neuiotms.dcam.workflow.model.LingyongConfrimSL;
import com.neusoft.neuiotms.dcam.workflow.model.LingyongSL;
import com.neusoft.neuiotms.dcam.workflow.repository.LingyongConfrimSLRepository;
import com.neusoft.neuiotms.dcam.workflow.repository.LingyongSLRepository;
import com.neusoft.neuiotms.dcam.workflow.service.LingyongSLService;
import com.neusoft.neuiotms.micro.auth.AuthMicroService;

import io.micrometer.core.instrument.util.StringUtils;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class LingyongSLServiceImpl implements LingyongSLService {

    @Autowired
    private WorkOrderService workOrderService;
    @Autowired
    private WorkOrderRepository workOrderRepository;
    @Autowired
    private ProcessInstanceService processInstanceService;
    @Autowired
    private LingyongSLRepository lingyongSLRepository;
    @Autowired
    private LingyongSLConverter lingyongSLConverter;
    @Autowired
    private AssetService assetService;
    @Autowired
    private LingyongConfrimSLRepository lingyongConfrimSLRepository;
    @Autowired
    private LingyongConfrimSLConverter lingyongConfrimSLConverter;
    @Autowired
    private AuthMicroService authMicroService;
    @Autowired
    private AssetRepository assetRepository;
    @Autowired
    private AssetConverter assetConverter;
    @Autowired
    private AssetLifeCycleService assetLifeCycleService;
    @Autowired
    private StorehouseService storehouseService;
    @Autowired
    private WarehouseRecordService warehouseRecordService;

    @Override
    @Transactional
    public LingyongSLDTO create(final LingyongSLDTO dto, final UserBean user) {

        final String taskId = dto.getTaskId();
        final ProcessInstanceDTO instance =
                this.workOrderService.submit(dto.getTitle(), DCAMConsts.PROCESSS_LINGYONG_SL_KEY,
                        dto.getWorkOrderNum(),
                        user);
        dto.setTaskId(instance.getTaskId());
        dto.setWorkOrderNum(instance.getWorkorderNum());
        dto.setCreateUser(user.getUsername());
        dto.setCreateUserName(user.getName());
        final List<String> orgs = user.getOrgs();
        if (orgs != null) {
            if (orgs.size() == 1) {
                dto.setOrgCode(orgs.get(0));
            } else if (orgs.size() > 1) {
                for (final String orgItem : orgs) {
                    if (orgItem.length() == 2) {
                        dto.setOrgCode(orgItem);
                        break;
                    }
                }
            }
            dto.setOrgName(this.authMicroService.orgInfoByCode(dto.getOrgCode()).getData().get("name").toString());
        }

        // 查询当前workOrderNum和TaskId下是否存在记录
        final LingyongSL oldModel = this.lingyongSLRepository.findByWorkOrderNumAndTaskId(
                dto.getWorkOrderNum(), taskId);
        if (oldModel == null) {
            dto.setId(null);
        }

        LingyongSL model = this.lingyongSLConverter.toModel(dto);
        model = this.lingyongSLRepository.save(model);

        // 确认节点审批人
        final List<String> users = new ArrayList<>();
        final Map<String, Object> search = new HashMap<>();
        search.put("s_orgCode", dto.getOrgCode());
        search.put("s_roleCode", AHConstants.ROLE_SL_DEPT_ASSET_ADMIN);
        final ResultListDTO<Map<String, Object>> userList = this.authMicroService.userIndex(search);
        userList.getData().stream().map(l -> l.get("username").toString()).filter(s -> null != s)
                .forEach(users::add);

        if (users.isEmpty()) {
            throw new UnitedException(dto.getOrgName() + "部门资产管理员不存在,联系系统管理员");
        }

        this.processInstanceService.setGlobalVariable(dto.getTaskId(), DCAMConsts.PROCESSS_DISPATCHUSERLIST,
                users);

        // 完成当前节点
        this.processInstanceService.complete(dto.getWorkOrderNum(), dto.getTaskId(), user);
        final LingyongSLDTO result = this.lingyongSLConverter.toDTO(model);

        return result;
    }

    @Override
    public LingyongSLDTO detail(final String workOrderNum, final String taskId, final UserBean user) {
        LingyongSL model = null;
        try {
            if (StringUtils.isNotBlank(workOrderNum) && !"NULL".equals(taskId)) {
                model = this.lingyongSLRepository.findByWorkOrderNumAndTaskId(workOrderNum, taskId);
                if (model == null) {
                    // 获取前一节点的TaskID
                    final String lastTaskId = this.processInstanceService.getLastTaskId(taskId, user);
                    if (lastTaskId == null) {
                        return new LingyongSLDTO();
                    } else {
                        model = this.lingyongSLRepository.findByWorkOrderNumAndTaskId(workOrderNum,
                                lastTaskId);
                    }
                }
            } else if ("NULL".equals(taskId)) {
                model = this.lingyongSLRepository.findTopByWorkOrderNumOrderByCreateTimeDesc(workOrderNum);
            }
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND,
                    new Object[] {workOrderNum },
                    new Object[] {taskId });
        }
        return this.lingyongSLConverter.toDTO(model);
    }

    @Override
    public void reject(final String workOrderNum) {

        // 解锁以前的资产信息
        final List<LingyongConfrimSL> all = this.lingyongConfrimSLRepository.findByWorkOrderNum(workOrderNum);
        if (null != all) {
            final List<Asset> list = all.stream().map(it -> {
                final Asset at = this.assetRepository.findByCode(it.getCode());
                at.setStatus(it.getStatus());
                at.setLocked(false);
                return at;
            }).collect(Collectors.toList());

            if (!all.isEmpty()) {
                this.assetRepository.saveAll(list);
            }
        }

    }

    @Override
    public List<LingyongConfrimSLDTO> confrimCreate(final List<LingyongConfrimSLDTO> dto, final UserBean user) {

        final List<LingyongConfrimSL> models = this.lingyongConfrimSLConverter.toListModel(dto);
        this.lingyongConfrimSLRepository.saveAll(models);

        // 枷锁资产
        this.assetService.updateLocked(dto.stream().map(l -> l.getCode()).distinct().collect(Collectors.toList()),
                true);

        // 完成当前节点
        this.processInstanceService.complete(dto.get(0).getWorkOrderNum(), dto.get(0).getTaskId(), user);

        //        final LingyongSL lingyong =
        //                this.lingyongSLRepository.findTopByWorkOrderNumOrderByCreateTimeDesc(dto.get(0).getWorkOrderNum());
        this.lingyongCompleteUpdate(dto, dto.get(0).getWorkOrderNum(), 1);
        //        this.lingyongCompleteUpdate(dto, lingyong.getOrgCode(), lingyong.getOrgName(), lingyong.getCategories());
        return this.lingyongConfrimSLConverter.toListDTO(models);

    }

    @Override
    public LingyongSLDTO confrimDetail(final String workOrderNum, final String taskId, final UserBean user) {
        LingyongSLDTO dto = new LingyongSLDTO();
        // 获取条件
        final LingyongSL lingyong =
                this.lingyongSLRepository.findTopByWorkOrderNumOrderByCreateTimeDesc(workOrderNum);
        if (lingyong != null) {
            dto = this.lingyongSLConverter.toDTO(lingyong);
        }

        List<LingyongConfrimSL> model = new ArrayList<>();
        try {
            if (StringUtils.isNotBlank(workOrderNum) && !"NULL".equals(taskId)) {
                model = this.lingyongConfrimSLRepository.findByWorkOrderNumAndTaskId(workOrderNum, taskId);
                dto.setLingyong(this.lingyongConfrimSLConverter.toListDTO(model));
            }
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND,
                    new Object[] {workOrderNum },
                    new Object[] {taskId });
        }
        final List<LingyongConfrimSLDTO> detailItems = dto.getLingyong();
        for (final LingyongConfrimSLDTO lingyongItemSL : detailItems) {
            final Asset asset = this.assetRepository.findByCode(lingyongItemSL.getCode());
            if (asset.getMoney() != null) {
                lingyongItemSL.setMoney(asset.getMoney());
            }
            lingyongItemSL.setPurpose(asset.getPurpose());
        }
        dto.setLingyong(detailItems);
        return dto;
    }

    @Override
    public List<LingyongConfrimSLDTO> distributeCreate(final List<LingyongConfrimSLDTO> dto, final UserBean user) {

        final List<LingyongConfrimSL> models = dto.stream().map(l -> {
            final LingyongConfrimSL model = this.lingyongConfrimSLRepository.getOne(l.getId());
            model.setLingyongUserCode(l.getLingyongUserCode());
            model.setLingyongUserName(l.getLingyongUserName());
            model.setLingyongLocation(l.getLingyongLocation());
            model.setLingyongLocationName(l.getLingyongLocationName());
            final Asset asset = this.assetRepository.findByCode(model.getCode());
            asset.setPurpose(l.getPurpose());
            this.assetRepository.save(asset);
            return model;
        }).collect(Collectors.toList());

        this.lingyongConfrimSLRepository.saveAll(models);

        this.processInstanceService.setGlobalVariable(dto.get(0).getTaskId(),
                "passFlag", true);

        this.processInstanceService.complete(dto.get(0).getWorkOrderNum(), dto.get(0).getTaskId(), user);

        this.lingyongCompleteUpdate(dto, dto.get(0).getWorkOrderNum(), 0);
        return this.lingyongConfrimSLConverter.toListDTO(models);
    }

    /**
     * @param dto
     * @param workOrderNum
     * @param flag 是否记录生命周期 1记录 0不记录
     */
    private void lingyongCompleteUpdate(final List<LingyongConfrimSLDTO> dto, final String workOrderNum,
            final int flag) {

        final List<AssetLifeCycleDTO> lifeList = new ArrayList<>();
        final List<WarehouseRecordDTO> records = new ArrayList<>();

        final List<Asset> saveData = new ArrayList<>();

        final LingyongSL lingyong =
                this.lingyongSLRepository.findTopByWorkOrderNumOrderByCreateTimeDesc(workOrderNum);

        switch (lingyong.getCategories()) {
        case "3":
            dto.stream().map(l -> {
                final List<Asset> list = new ArrayList<>();
                final Asset model = this.assetRepository.findByCode(l.getCode());
                model.setAmount(model.getAmount() - l.getLingyongQuantity());
                model.setLocked(false);
                list.add(model);

                // 判断是否为库房
                if (this.storehouseService.LocationIsStorehouse(model.getLocation())) {
                    records.add(WarehouseRecordDTO.builder()
                            .name(model.getName())
                            .specifications(model.getSpecifications())
                            .brand(model.getBrand())
                            .smallTypeName(model.getSmallTypeName())
                            .smallTypeCode(model.getSmallTypeName()).contractNo(model.getContractNo())
                            .contractName(model.getContractName()).amount(l.getLingyongQuantity())
                            .location(model.getLocation())
                            .locationName(model.getLocationName()).type("2").build());
                }

                final Asset xh =
                        this.assetRepository
                                .findTopBySmallTypeCodeAndSpecificationsAndManagementOrgCodeOrderByCreateTimeDesc(
                                        l.getSmallTypeCode(), l.getSpecifications(), lingyong.getOrgCode());
                if (xh != null) {
                    xh.setAmount(xh.getAmount() + l.getLingyongQuantity());
                    list.add(xh);

                    // 生命周期
                    lifeList.add(AssetLifeCycleDTO.builder().code(xh.getCode())
                            .lifeCycle(DCAMConsts.ASSET_LIFE_TYPE_JILU)
                            .content("数量为" + l.getLingyongQuantity() + "的" + l.getSmallTypeName() + "已领用")
                            .workNum(lingyong.getWorkOrderNum()).build());

                } else {
                    AssetDTO assetDTO = this.assetConverter.toDTO(model);
                    assetDTO.setId(null);
                    assetDTO.setAmount(l.getLingyongQuantity());
                    assetDTO.setManagementOrgName(lingyong.getOrgName());
                    assetDTO.setManagementOrgCode(lingyong.getOrgCode());
                    assetDTO.setAmount(0);
                    assetDTO = this.assetService.create(assetDTO, null, null);

                    // 生命周期
                    lifeList.add(AssetLifeCycleDTO.builder().code(assetDTO.getCode())
                            .lifeCycle(DCAMConsts.ASSET_LIFE_TYPE_JILU)
                            .content("数量为" + l.getLingyongQuantity() + "的" + l.getSmallTypeName() + "已领用")
                            .workNum(lingyong.getWorkOrderNum()).build());
                }

                // 生命周期
                lifeList.add(AssetLifeCycleDTO.builder().code(l.getCode())
                        .lifeCycle(DCAMConsts.ASSET_LIFE_TYPE_JILU)
                        .content("数量为" + l.getLingyongQuantity() + "的" + l.getSmallTypeName() + "已发给"
                                + lingyong.getOrgName() + "部门")
                        .workNum(lingyong.getWorkOrderNum()).build());
                return model;
            }).collect(Collectors.toList());

            break;
        default:
            dto.stream().map(l -> {
                final Asset model = this.assetRepository.findByCode(l.getCode());
                model.setManagementUserCode(l.getLingyongUserCode());
                model.setManagementUserName(l.getLingyongUserName());
                model.setManagementOrgCode(lingyong.getOrgCode());
                model.setManagementOrgName(lingyong.getOrgName());
                model.setLocation(l.getLingyongLocation());
                model.setLocationName(l.getLingyongLocationName());
                if (StringUtils.isNotEmpty(l.getLingyongUserCode())) {
                    model.setStatus(DCAMConsts.ASSET_STATUS_USED);
                    if (flag == 1) {
                        // 生命周期
                        lifeList.add(AssetLifeCycleDTO.builder().code(model.getCode())
                                .lifeCycle(DCAMConsts.ASSET_LIFE_TYPE_LINGYONG).workNum(lingyong.getWorkOrderNum())
                                .content(model.getName() + "已被领用").build());
                    }

                } else {
                    model.setStatus(DCAMConsts.ASSET_STATUS_USED);
                    if (flag == 1) {
                        // 生命周期
                        lifeList.add(AssetLifeCycleDTO.builder().code(model.getCode())
                                .lifeCycle(DCAMConsts.ASSET_LIFE_TYPE_LINGYONG)
                                .content(model.getName() + "已被领用")
                                .workNum(dto.get(0).getWorkOrderNum()).build());
                    }
                }
                model.setLocked(false);
                return model;
            }).forEach(saveData::add);

            break;
        }

        if ((saveData != null) && (saveData.size() > 0)) {
            this.assetRepository.saveAll(saveData);
        }

        if (records.size() > 0) {
            this.warehouseRecordService.batchCreate(records);
        }

        if (lifeList.size() > 0) {
            this.assetLifeCycleService.batchCreate(lifeList);
        }

    }

    @Override
    public LingyongSLDTO distributeDetail(final String workOrderNum, final String taskId,
            final UserBean user) {

        final LingyongSL lingyong =
                this.lingyongSLRepository.findTopByWorkOrderNumOrderByCreateTimeDesc(workOrderNum);
        final LingyongSLDTO dto = this.lingyongSLConverter.toDTO(lingyong);

        List<LingyongConfrimSL> model = new ArrayList<>();
        try {
            if (StringUtils.isNotBlank(workOrderNum) && !"NULL".equals(taskId)) {
                model = this.lingyongConfrimSLRepository.findByWorkOrderNumOrderByIdDesc(workOrderNum);
                final String lastTaskId = model.get(0).getTaskId();
                model = model.stream().filter(it -> lastTaskId.equals(it.getTaskId())).collect(Collectors.toList());

                dto.setLingyong(this.lingyongConfrimSLConverter.toListDTO(model));
            }
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND,
                    new Object[] {workOrderNum },
                    new Object[] {taskId });
        }

        //        final PeifaSLDTO modelDto = this.peifaSLConverter.toDTO(model);
        final List<LingyongConfrimSLDTO> detailItems = dto.getLingyong();
        for (final LingyongConfrimSLDTO lingyongItemSL : detailItems) {
            final Asset asset = this.assetRepository.findByCode(lingyongItemSL.getCode());
            if (asset.getMoney() != null) {
                lingyongItemSL.setMoney(asset.getMoney());
            }
            lingyongItemSL.setPurpose(asset.getPurpose());
        }
        dto.setLingyong(detailItems);
        return dto;
    }

    @Override
    public List<LingyongSLDTO> search(final Searchable searchable) {
        final List<LingyongSL> models = this.lingyongSLRepository.search(searchable);
        return this.lingyongSLConverter.toListDTO(models);
    }

    @Override
    public Page<LingyongSLDTO> search(final Pageable pageable, final Searchable searchable) {
        final Searchable params = new Searchable();
        params.put("type", "LingyongSL");
        params.put("status", "finish");
        final List<WorkOrder> finishedWorkorderList = this.workOrderRepository.search(params);
        final List<String> finishedWorkorderWorkNumList =
                finishedWorkorderList.stream().map(it -> it.getWorkOrderNum()).collect(Collectors.toList());

        searchable.put("workOrderNumIn", finishedWorkorderWorkNumList);
        final Page<LingyongSL> models = this.lingyongSLRepository.search(pageable, searchable);
        final Page<LingyongSLDTO> dtos = this.lingyongSLConverter.toPageDTO(models);
        return dtos;
    }

    @Override
    public LingyongSLDTO detail(final Long id) {
        final LingyongSL model = this.lingyongSLRepository.findById(id).orElse(null);
        if (null != model) {
            final LingyongSLDTO dto = this.lingyongSLConverter.toDTO(model);
            List<LingyongConfrimSL> lingyongAssetList = new ArrayList<>();
            try {
                if (StringUtils.isNotBlank(model.getWorkOrderNum())) {
                    lingyongAssetList = this.lingyongConfrimSLRepository.findByWorkOrderNum(model.getWorkOrderNum());
                    dto.setLingyong(this.lingyongConfrimSLConverter.toListDTO(lingyongAssetList));
                }
            } catch (final EntityNotFoundException e) {
                LingyongSLServiceImpl.log.error("", e);
            }
            final List<LingyongConfrimSLDTO> detailItems = dto.getLingyong();

            final List<String> assetCodeList =
                    detailItems.stream().map(it -> it.getCode()).collect(Collectors.toList());
            final Searchable params = new Searchable();
            params.put("codes", assetCodeList);
            final List<AssetDTO> assetList = this.assetService.index(params);
            dto.setAssetStandingBook(assetList);

            //            for (final LingyongConfrimSLDTO lingyongItemSL : detailItems) {
            //                final Asset asset = this.assetRepository.findByCode(lingyongItemSL.getCode());
            //                if (asset.getMoney() != null) {
            //                    lingyongItemSL.setMoney(asset.getMoney());
            //                }
            //                lingyongItemSL.setPurpose(asset.getPurpose());
            //                lingyongItemSL.setMeasureUnit(asset.getMeasureUnit());
            //            }
            //            dto.setLingyong(detailItems);
            return dto;
        }
        return null;
    }

}
